import * as Cesium from "cesium";
import {
  getPositionHeight,
  get2PositionDistance,
  generateCirclePoints,
  cartesian3ToDegreesHeight,
} from "./utils";
import _ from "lodash";

class DrawTool {
  constructor(viewer) {
    this.viewer = viewer
    // 初始化handler,events
    this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas)
    this.DrawStartEvent = new Cesium.Event() //开始绘制事件
    this.DrawEndEvent = new Cesium.Event() //结束绘制事件
  }

  DrawTypes = {
    Polyline: 'Polyline',
    Rectangle: 'Rectangle',
    Point: 'Point',
    Circle: 'Circle',
    Polygon: 'Polygon',
  }

  // 激活绘制工具，传入DrawType
  active(drawType) {
    // 如果在我们的绘制工具集合中，存在这个工具
    if (Object.keys(this.DrawTypes).includes(drawType)) {
      this.drawType = drawType
      // 最终的坐标
      this.positions = []
      // 绘制过程中的坐标
      this.curPositions = []
      // 每次点击有一个标点，需要存储实体
      this.points = []
      // 注册鼠标事件
      this.registerEvents()

      //禁用鼠标默认样式
      this.viewer.enableCursorStyle = false
      this.viewer._element.style.cursor = 'default'
      this.DrawStartEvent.raiseEvent('开始绘制')
      this.createMarker(drawType)
    } else {
      return
    }
  }
  // 添加提示信息
  createMarker(drawType) {
    this.marker = document.createElement('div')
    const hintMap = {
      Point: '左键点击添加一个点',
      Polyline: '左键点击添加节点，右键完成绘制折线',
      Rectangle: '左键点击两个点确定矩形对角线，右键完成',
      Circle: '左键点击圆心，再点击一点确定半径，右键完成',
      Polygon: '左键点击添加节点，右键闭合多边形',
    }
    this.marker.innerHTML = hintMap[drawType] || ''
    
    this.marker.className = 'marker-draw'
    this.viewer.cesiumWidget.container.appendChild(this.marker)
  }

  destoryMarker() {
    this.marker && this.viewer.cesiumWidget.container.removeChild(this.marker)
    this.marker = null
  }
  // 注册鼠标事件 分别注册左键画点，右键结束画点，鼠标移动事件
  registerEvents() {
    this.leftClickEvent()
    this.rightClickEvent()
    this.mouseMoveEvent()
  }

  // 坐标转换:屏幕坐标转笛卡尔 pickPosition比 pickEllipsoid 精度更高,优先使用
  positionTransfer(position) {
    let resultPosition = this.viewer.scene.pickPosition(position)
    // Cesium.defined是 Cesium 提供的一个工具函数，用来安全判断一个值是否存在。
    if (!Cesium.defined(resultPosition)) {
      resultPosition = this.viewer.scene.camera.pickEllipsoid(position, this.viewer.scene.globe.ellipsoid)
    }
    return resultPosition
  }

  leftClickEvent() {
    // 单机鼠标左键画点
    this.handler.setInputAction((e) => {
      let position = this.positionTransfer(e.position)
      if (!position) return
      this.positions.push(position)
      this.curPositions.push(position)
      // 根据传入drawType，绘制图案
      if (this.positions.length === 1) {
        this.startDraw()
      }
      //  如果是画线或者画点，每次点击左键，都在同一位置画一个点
      if (this.drawType === this.DrawTypes.Polyline || this.drawType === this.DrawTypes.Point) {
        this.generatePoint(position)
      }
    }, Cesium.ScreenSpaceEventType.LEFT_CLICK)
  }

  //   鼠标移动事件
  mouseMoveEvent() {
    this.handler.setInputAction((e) => {
      this.marker.style.left = e.endPosition.x + 20 + 'px'
      this.marker.style.top = e.endPosition.y - 20 + 'px'
      // 鼠标移动时修改cesium的手柄样式为默认样式
      this.viewer._element.style.cursor = 'default' 
      let position = this.positionTransfer(e.endPosition)
      if (!position || !this.drawEntity) return
      this.curPositions = [...this.positions, position]
    }, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
  }

  //   右键点击，结束绘制
  rightClickEvent() {
    this.handler.setInputAction(() => {
      // 如果还没有开始绘制，直接结束绘制状态
      if (!this.drawEntity) {
        this.deactive()
        return
      }
      // 如果当前的坐标数量少于最小数量，直接结束
      if (this.positions.length < this.minPositionCount) {
        this.deactive()
        return
      }
      // 根据各种绘制类型，要重新给坐标赋值，把callback变为constant
      switch (this.drawType) {
        case this.DrawTypes.Polyline:
          this.drawEntity.polyline.positions = this.positions
          break
        case this.DrawTypes.Rectangle:
          this.drawEntity.polygon.hierarchy = new Cesium.PolygonHierarchy(this.getRectangleFourPoints())
          this.drawEntity.polyline.positions = this.getRectangleFourPoints()
          this.positions = this.getRectangleFourPoints()
          this.positions.pop()
          break
        case this.DrawTypes.Circle:
          this.drawEntity.ellipse.semiMinorAxis = this.getAxis()
          this.drawEntity.ellipse.semiMajorAxis = this.getAxis()
          this.minPositionCount = 2
          break
        case this.DrawTypes.Polygon:
          console.log(this.positions)
          this.drawEntity.polygon.hierarchy = new Cesium.PolygonHierarchy(this.positions.concat(this.positions[0]))
          this.drawEntity.polyline.positions = this.positions.concat(this.positions[0])
          break
        default:
          break
      }
      this.deactive()
    }, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
  }

  startDraw() {
    switch (this.drawType) {
      case this.DrawTypes.Point:
        // 对于点，直接结束绘制就完事了
        this.drawEntity = this.generatePoint(this.positions[0])
        this.minPositionCount = 1
        break
      case this.DrawTypes.Polyline:
        this.generatePolyline()
        this.minPositionCount = 2
        break
      case this.DrawTypes.Rectangle:
        this.generateRectangle()
        this.minPositionCount = 2
        break
      case this.DrawTypes.Circle:
        this.generateCircle()
        this.minPositionCount = 2
        break
      case this.DrawTypes.Polygon:
        this.generatePolygon()
        this.minPositionCount = 3
        break
      default:
        break;
    }
  }
  // 绘制点
  generatePoint(position) {
    console.log(position)
    const cartographic = Cesium.Cartographic.fromCartesian(position)
    console.log(cartographic)
    const point = this.viewer.entities.add({
      Type: this.DrawTypes.Point,
      position: position,
      point: {
        pixelSize: 14,
        color: Cesium.Color.RED,
      },
    })
    this.points.push(point)
    return point
  }

  //   绘制线,position使用callbackProperty动态更新
  generatePolyline() {
    this.drawEntity = this.viewer.entities.add({
      Type: this.DrawTypes.Polyline,
      polyline: {
        positions: new Cesium.CallbackProperty((e) => {
          return this.curPositions
        }, false),
        width: 2,
        // 使用cesium的虚线材质
        material: new Cesium.PolylineDashMaterialProperty({
          color: Cesium.Color.YELLOW,
        }),
        clampToGround: true,
      },
    })
  }

  //   绘制矩形，由polygon和polyline组成
  generateRectangle() {
    this.drawEntity = this.viewer.entities.add({
      Type: this.DrawTypes.Rectangle,
      polygon: {
        hierarchy: new Cesium.CallbackProperty((e) => {
          return new Cesium.PolygonHierarchy(this.getRectangleFourPoints())
        }, false),
        material: Cesium.Color.RED.withAlpha(0.6),
        perPositionHeight: true,
      },
      polyline: {
        positions: new Cesium.CallbackProperty((e) => {
          return this.getRectangleFourPoints()
        }, false),
        width: 1,
        material: new Cesium.PolylineDashMaterialProperty({
          color: Cesium.Color.YELLOW,
        }),
        // 地形遮挡时线显示颜色
        depthFailMaterial: new Cesium.PolylineDashMaterialProperty({
          color: Cesium.Color.YELLOW,
        }),
      },
    })
  }

  // 获取矩形四个点
  getRectangleFourPoints() {
    if (this.curPositions.length) {
      // 鼠标点击一次时，curPositions只有一个坐标,让两个点取相同的坐标,防止报错,点击第二个点时正常赋值
      let p1 = this.curPositions[0]
      let p2 = this.curPositions[0]
      if (this.curPositions.length > 1) {
        p2 = this.curPositions[1]
      } 

      let c1 = Cesium.Cartographic.fromCartesian(p1)
      let c2 = Cesium.Cartographic.fromCartesian(p2)
      // 保证高度为正
      if (c1.height < 0) c1.height = 0
      if (c2.height < 0) c2.height = 0
      let lls = this.getRectanglePointsByTwoPoint(c1, c2)

      // 坐标数组转为指定格式
      let ars =
        [ lls[0][0], lls[0][1], c1.height, //点1
          lls[1][0], lls[1][1], c1.height, //点2
          lls[2][0], lls[2][1], c1.height, //点3
          lls[3][0], lls[3][1], c1.height, //点4
          lls[0][0], lls[0][1], c1.height // 回到点1,闭合轮廓 
        ]
      // 坐标数组转为笛卡尔坐标
      const result = Cesium.Cartesian3.fromDegreesArrayHeights(ars)
      return result
    }
  }

  //   获取矩形四个点
  getRectanglePointsByTwoPoint(c1, c2) {
    //转为经纬度
    let lngLat1 = [Cesium.Math.toDegrees(c1.longitude), Cesium.Math.toDegrees(c1.latitude)]
    let lngLat2 = [Cesium.Math.toDegrees(c2.longitude), Cesium.Math.toDegrees(c2.latitude)]

    let lngLat3 = [Cesium.Math.toDegrees(c1.longitude), Cesium.Math.toDegrees(c2.latitude)]
    let lngLat4 = [Cesium.Math.toDegrees(c2.longitude), Cesium.Math.toDegrees(c1.latitude)]

    return [lngLat1, lngLat3, lngLat2, lngLat4]
  }

  // 绘制多边形
  generatePolygon() {
    this.drawEntity = this.viewer.entities.add({
      Type: this.DrawTypes.Polygon,
      polygon: {
        hierarchy: new Cesium.CallbackProperty((e) => {
          return new Cesium.PolygonHierarchy(this.curPositions.concat(this.curPositions[0]))
        }, false),
        material: Cesium.Color.RED.withAlpha(0.6),
        classificationType: Cesium.ClassificationType.BOTH,
      },
      polyline: {
        positions: new Cesium.CallbackProperty((e) => {
          return this.curPositions.concat(this.curPositions[0])
        }, false),
        width: 1,
        material: new Cesium.PolylineDashMaterialProperty({
          color: Cesium.Color.YELLOW,
        }),
        depthFailMaterial: new Cesium.PolylineDashMaterialProperty({
          color: Cesium.Color.YELLOW,
        }),
        clampToGround: true,
      },
    })
  }

  // 绘制圆
  generateCircle() {
    this.drawEntity = this.viewer.entities.add({
      position: this.positions[0],
      ellipse: {
        height: getPositionHeight(this.positions[0]),
        semiMinorAxis: new Cesium.CallbackProperty((e) => {
          return this.getAxis()
        }, false),
        semiMajorAxis: new Cesium.CallbackProperty((e) => {
          return this.getAxis()
        }, false),
        material: Cesium.Color.RED.withAlpha(0.6),
      },
    })
  }

  //圆半径
  getAxis() {
    if (this.curPositions.length) {
      let p1 = this.curPositions[0]
      let p2 = this.curPositions[0]
      if (this.curPositions.length > 1) {
        p2 = this.curPositions[this.curPositions.length - 1]
      } 
      const axis = get2PositionDistance(p1, p2)
      return axis
    }
  }

  // 结束绘制
  deactive() {
    // 对于圆，根据半径计算边缘点坐标并返回
    let points = []
    if (this.drawType === this.DrawTypes.Circle) {
      const radius = this.getAxis()
      const positions = cartesian3ToDegreesHeight(this.positions[0])
      points = generateCirclePoints(positions, radius)
      points = points.map((item) => {
        const height = getPositionHeight(this.positions[0])
        return Cesium.Cartesian3.fromDegrees(item[0], item[1], height)
      })
    }

    // 提交绘制结束事件
    this.DrawEndEvent.raiseEvent(this.drawEntity, this.positions, this.drawType, points)
    this.unRegisterEvents()
    this.destoryMarker()
    // this.drawType = undefined;
    // this.drawEntity = undefined;
    // this.positions = [];
    // this.curPositions = [];
    this.viewer._element.style.cursor = 'pointer'
    this.viewer.enableCursorStyle = true
  }

  //移除鼠标事件
  unRegisterEvents() {
    this.handler.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK)
    this.handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK)
    this.handler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE)
    this.handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK)
  }

  //   清除绘制的实体
  removeAllDrawEnts() {
    this.points &&
      this.points.forEach((point) => {
        this.viewer.entities.remove(point)
      })
    this.drawEntity && this.viewer.entities.remove(this.drawEntity)
    this.points = []
    this.drawEntity = null
  }

  removeListener(event) {
    this.DrawEndEvent && this.DrawEndEvent.numberOfListeners && this.DrawEndEvent.removeEventListener(event)
  }
}

export default DrawTool;
